/**
 * Type implementaion
 *
 * \file type.cpp
 * \author tomby
 * \date 04-01-2009
 **/

/*  Copyright (C) 2009  Tomas 'tomby' Bily

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>. */

#include <stdio.h>
#include <iostream>
#include <map>
#include <boost/pool/pool_alloc.hpp>
#include "dbc-sys.hpp"

using namespace dbc;
using namespace std;

#if 0
/// SIGSEGV something wrong with global ctors and stdc++, @todo: examine more 

typedef map<const string, unsigned long, equal_to<const string> > RegistryType; 

static RegistryType type_registry;
static unsigned long id_registry = 0;

static unsigned long
reg_type (const string& s)
{
  RegistryType::iterator i = type_registry.find (s);

  if (i == type_registry.end ())
    {
      /// @todo: do more sophisticated id assignment independent on
      /// order and machine
      unsigned long id = id_registry ++;
      type_registry [s] = id;
      
      return id;
    }

  return (*i).second;
}
#else
/// Maybe rewrite to splay tree ;)

typedef vector<string> RegistryType; 
typedef vector<unsigned long> IdRegistry;

static RegistryType type_registry;
static IdRegistry id_type_registry;
static unsigned long id_registry = 0;

static unsigned long
reg_type (const string& s)
{
  RegistryType::iterator i;
  int j = 0;

  for (i = type_registry.begin (); i != type_registry.end (); ++i, ++j) 
    if (*i == s)
      break;

  if (i == type_registry.end ())
    {
      /// @todo: do more sophisticated id assignment independent on
      /// order and machine
      unsigned long id = id_registry ++;
      type_registry.push_back (s);
      id_type_registry.push_back (id);

      printf ("Type %s is registered with id: %ld\n", s.c_str (), id);

      return id;
    }

  return id_type_registry [j];
}
#endif

Type::Type (const char* iname)
  : name (iname), multi_ator (0)
{ type_id = reg_type (name); ancestors.ator = NULL; }

Type::Type (const char* iname, const Type* ator)
  : name (iname), multi_ator (0)
{ type_id = reg_type (name); ancestors.ator = ator; }

Type::Type (const char* iname, const Type* ator1, const Type* ator2)
  : name (iname), multi_ator (1)
{
  type_id = reg_type (name); 
  ancestors.ators = boost::fast_pool_allocator<const Type*>::allocate (3);
  ancestors.ators [0] = ator1;
  ancestors.ators [1] = ator2;
  ancestors.ators [2] = NULL;
}

Type::Type (const char* iname, const Type* ator1, const Type* ator2, const Type* ator3)
  : name (iname), multi_ator (1)
{
  type_id = reg_type (name); 
  ancestors.ators = boost::fast_pool_allocator<const Type*>::allocate (4);
  ancestors.ators [0] = ator1;
  ancestors.ators [1] = ator2;
  ancestors.ators [2] = ator3;
  ancestors.ators [3] = NULL;
}

Type::Type (const char* iname, const Type* ator1, const Type* ator2, const Type* ator3, const Type* ator4)
  : name (iname), multi_ator (1)
{
  type_id = reg_type (name); 
  ancestors.ators = boost::fast_pool_allocator<const Type*>::allocate (5);
  ancestors.ators [0] = ator1;
  ancestors.ators [1] = ator2;
  ancestors.ators [2] = ator3;
  ancestors.ators [3] = ator4;
  ancestors.ators [4] = NULL;
}

bool 
Type::is_type_of (Type const& t, Type const* self)
{
  if (self == NULL)
    return false;

  if (*self == t)
    return true;

  if (self->multi_ator)
    {
      for (int i = 0; self->ancestors.ators [i] != NULL; i++)
	if (is_type_of (t, self->ancestors.ators [i]))
	  return true;
    }
  else
    return is_type_of (t, self->ancestors.ator);

  return false;
}

